package com.fitz.registry.nacos;

import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.fitz.registry.DefaultRegistry;
import com.fitz.registry.InstanceInfo;
import com.fitz.registry.InstanceRegistry;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;

/**
 * @author gousl01
 * @date 2021/4/30 14:34
 * @desc
 */
@Slf4j
public class NacosRegistry extends DefaultRegistry implements InstanceRegistry {


    private NamingService namingService;

    public NacosRegistry(String registryAddress){
        try {
            Properties properties = new Properties();
            properties.put(SERVER_ADDR, registryAddress);
            this.namingService = NamingFactory.createNamingService(properties);
        } catch (NacosException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void register(InstanceInfo instance) {
        HashMap<String,Object> handlerMap = instance.getHandlerMap();
        for (Map.Entry<String, Object> entry : handlerMap.entrySet()){
            String serviceName = entry.getKey();
            Instance nacosInstance = new Instance();
            nacosInstance.setPort(instance.getPort());
            nacosInstance.setIp(instance.getHost());
            nacosInstance.setServiceName(serviceName);
            nacosInstance.setInstanceId(UUID.randomUUID().toString().replace("-", ""));
            try {
                namingService.registerInstance(serviceName,nacosInstance);
            } catch (NacosException e) {
                log.error("Nacos注册服务异常:", e);
            }
        }
    }

    @Override
    public void deRegister(InstanceInfo instance) {
        Instance nacosInstance = new Instance();
        nacosInstance.setPort(instance.getPort());
        nacosInstance.setIp(instance.getHost());
        try {
            namingService.deregisterInstance(instance.getServiceName(),nacosInstance);
        } catch (NacosException e) {
            log.error("Nacos注销服务异常:", e);
        }
    }

    @Override
    public List<InstanceInfo> getAllInstances(String serviceName) {
        List<Instance> list = null;
        try {
            list = namingService.getAllInstances(serviceName);
        } catch (NacosException e) {
            log.error("Nacos获取所有[{}]服务实例异常:",serviceName, e);
        }
        List<InstanceInfo> instanceInfos = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(list)){
//            setInstances(assemble(list));
            instanceInfos = assemble(list);
            serviceInfoMap.put(serviceName,instanceInfos);
        }
        return instanceInfos;
    }

    @Override
    public void subscribe(String serviceName) {
        try {
            namingService.subscribe(serviceName, event -> {
                if (event instanceof NamingEvent) {
                    List<Instance> list = ((NamingEvent) event).getInstances();
//                    setInstances(assemble(list));
                    serviceInfoMap.put(serviceName,assemble(list));
                }
            });
        } catch (NacosException e) {
            log.error("Nacos订阅[{}]服务实例异常:",serviceName, e);
        }
    }

    @Override
    public void unSubscribe(String serviceName) {

    }

    private List<InstanceInfo> assemble(List<Instance> list){
        List<InstanceInfo> instances = new ArrayList<>();
        list.forEach(instance-> {
            InstanceInfo instanceInfo = new InstanceInfo();
            instanceInfo.setServiceName(instance.getServiceName());
            instanceInfo.setHost(instance.getIp());
            instanceInfo.setPort(instance.getPort());
            instanceInfo.setAlive(instance.isEnabled());
            instances.add(instanceInfo);
        });
        return instances;
    }
}
